The Decorator Pattern attaches additional responsibilities to an object dynamically.
Decorator provide a flexible alternative to subclassing for extending functionality.
Also known as Wrapper. It involves a set of decorator classes that are used to wrap concrete components.
Key Points
- Decorators have the same supertype as the objects they decorate.
- One or more decorators can be used to decorate an object.
- As the decorator has the same supertype as the object it decorates, we can pass around the decorated object in place of original object .
- **The Decorator adds its own behaviour before and/or after delegating to the object it decorates to do the rest of the job. **
- It uses composition.
- Objects can be dynamically decorated at runtime.
public abstract class Beverage {
String description;
public String getDescription() {
return description;
}
public abstract double cost();
}
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
@Override
public double cost() {
return 0;
}
}
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return 0.50 + beverage.cost();
}
@Override
public String getDescription() {
return beverage.getDescription() + "Mocha.";
}
}
// USAGE
Beverage espresso = new Espresso();
Beverage espressoWithMocha = new Mocha(espresso);
Beverage espressoWithDoubleMocha = new Mocha(espressoWithMocha);
Examples in JAVA API.
java.io package is largely based on decorator.
BufferedInputStream and LineNumberInputStream both extend FilterInputStream, which acts as the abstract decorator class.
public class LowerCaseInputStream extends FilterInputStream {
public LowerCaseInputStream(InputStream in) {
super(in);
}
public int read() throws IOException {
int c = super.read();
return (c== -1 ? c : Character.toLowerCase((char)c));
}
}
//Example
InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("input.txt")));